package com.health.system.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.health.system.common.utils.IpUtil;
import com.health.system.common.utils.UserAuthUtil;
import com.health.system.convert.UserConvert;
import com.health.system.dto.UserHomeDTO;
import com.health.system.dto.UserOnlineDTO;
import com.health.system.entity.UserInfo;
import com.health.system.mapper.UserInfoMapper;
import com.health.system.security.auth.entity.HealthSecurityAuthDetails;
import com.health.system.service.UserInfoService;
import com.health.system.vo.ModifyUserInfoVo;
import com.health.system.vo.UserOnlineListPageSearchVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author huangye
 * @since 2022-10-21
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    private static final UserConvert INSTANCE = UserConvert.INSTANCE;

    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private SessionRegistry sessionRegistry;
    @Autowired
    private RedisService redisService;

    @Override
    public void updateInfoById(ModifyUserInfoVo vo) {
        UserInfo info = INSTANCE.covert(vo);
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, UserAuthUtil.authId());

        userInfoMapper.update(info, wrapper);
    }

    @Override
    public void offline(Long userInfoId) {
        List<SessionInformation> allSessions = new ArrayList<>();

        sessionRegistry.getAllPrincipals().stream().filter(item -> {
            HealthSecurityAuthDetails details = (HealthSecurityAuthDetails) item;
            return details.getUserInfoId().equals(userInfoId);
        }).collect(Collectors.toList()).forEach(item -> allSessions.addAll(sessionRegistry.getAllSessions(item, false)));

        // 注销session
        allSessions.forEach(SessionInformation::expireNow);
    }

    @Override
    public List<UserOnlineDTO> onlineListPage(Long current, Long size, UserOnlineListPageSearchVo condition) {
        return sessionRegistry.getAllPrincipals().stream()
                .filter(item -> !sessionRegistry.getAllSessions(item, false).isEmpty())
                .map(item -> covertUserInfo((HealthSecurityAuthDetails) item))
                .filter(item -> StringUtils.isBlank(condition.getKeyword()) || item.getNickName().contains(condition.getKeyword()))
                .collect(Collectors.toList());
    }

    private UserOnlineDTO covertUserInfo(HealthSecurityAuthDetails item) {
        UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getId, item.getUserInfoId()));
        return UserOnlineDTO.builder()
                .userInfoId(userInfo.getId())
                .avatar(userInfo.getAvatar())
                .nickName(userInfo.getNickname())
                .ipAddress(IpUtil.getIpAddress())
                .ipSource(IpUtil.getIpSource())
                .lastLoginTime(item.getLastLoginTime())
                .build();
    }

    private static Map<Object, Object> buildRedisValues(UserHomeDTO result) {
        Map<Object, Object> values = new HashMap<>(6);
        values.put("avatar", result.getAvatar());
        values.put("nickName", result.getNickName());
        values.put("intro", result.getIntro());
        values.put("articleCount", Convert.toStr(result.getArticleCount()));
        values.put("categoryCount", Convert.toStr(result.getCategoryCount()));
        values.put("tagCount", Convert.toStr(result.getTagCount()));
        return values;
    }

    private static UserHomeDTO buildRedisResultData(Map<Object, Object> userMap) {
        return UserHomeDTO.builder()
                .avatar(Convert.toStr(userMap.get("avatar")))
                .nickName(Convert.toStr(userMap.get("nickName")))
                .intro(Convert.toStr(userMap.get("intro")))
                .articleCount(Convert.toInt(userMap.get("articleCount")))
                .categoryCount(Convert.toInt(userMap.get("categoryCount")))
                .tagCount(Convert.toInt(userMap.get("tagCount")))
                .build();
    }
}
